/*
 * PHPWind util Library
 * @Copyright 	: Copyright 2011, phpwind.com
 * @Descript	: datePicker 日历组件
 * @Author		: jquerytools (http://jquerytools.org/demos/dateinput/)
 * @Modify		: chaoren1641@gmail.com
 * @Depend		: jquery.js(1.7 or later)
 * $Id: datePicker.js 22586 2012-12-25 10:54:55Z hao.lin $			:
 */
;(function ($, window, document, undefined) {
    var pluginName = 'datePicker';
    var instances = [];

    // h=72, j=74, k=75, l=76, down=40, left=37, up=38, right=39
    var KEYS = [75, 76, 38, 39, 74, 72, 40, 37], LABELS = {};
    var defaults = {
        format: 'yyyy-mm-dd',
        selectors: true,
        time: false,
        yearRange: [-200, 200],
        lang: 'zh-CN',
        offset: [0, 0],
        speed: 0,
        firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
        min: undefined,
        max: undefined,
        trigger: false,

        css: {

            prefix: 'cal',
            input: 'date',

            // ids
            root: 0,
            head: 0,
            title: 0,
            prev: 0,
            next: 0,
            month: 0,
            year: 0,
            days: 0,

            body: 0,
            weeks: 0,
            today: 0,
            current: 0,

            // classnames
            week: 0,
            off: 0,
            sunday: 0,
            focus: 0,
            disabled: 0,
            trigger: 0
        }
    };

    var localize = function (language, labels) {
        $.each(labels, function (key, val) {
            labels[key] = val.split(",");
        });
        LABELS[language] = labels;
    };

    //多语言配置
    localize("en", {
        months: 'January,February,March,April,May,June,July,August,September,October,November,December',
        shortMonths: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec',
        days: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday',
        shortDays: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'
    });
    localize("zh-CN", {
        months: '一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月',
        shortMonths: '一,二,三,四,五,六,七,八,九,十,十一,十二',
        days: '周日,周一,周二,周三,周四,周五,周六',
        shortDays: '日,一,二,三,四,五,六'
    });

    //{{{ private functions

    //返回某年某月的天数
    function dayAm(year, month) {
        return 32 - new Date(year, month, 32).getDate();
    }

    function zeropad(val, len) {
        val = '' + val;
        len = len || 2;
        while (val.length < len) {
            val = "0" + val;
        }
        return val;
    }

    // thanks: http://stevenlevithan.com/assets/misc/date.format.js
    var Re = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, tmpTag = $("<a/>");

    //格式化时间
    function format(date, fmt, lang) {
        var d = date.getDate(), D = date.getDay(), m = date.getMonth(), y = date.getFullYear(),
            h = date.getHours(), M = date.getMinutes(),
            flags = {
                d: d,
                dd: zeropad(d),
                ddd: LABELS[lang].shortDays[D],
                dddd: LABELS[lang].days[D],
                m: m + 1,
                mm: zeropad(m + 1),
                mmm: LABELS[lang].shortMonths[m],
                mmmm: LABELS[lang].months[m],
                yy: String(y).slice(2),
                yyyy: y,
                HH: zeropad(h),
                MM: zeropad(M)
            };
        var ret = fmt.replace(Re, function ($0) {
            return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
        });
        // a small trick to handle special characters
        return tmpTag.html(ret).html();

    }

    function integer(val) {
        return parseInt(val, 10);
    }

    function isSameDay(d1, d2) {
        return d1.getFullYear() === d2.getFullYear() && d1.getMonth() == d2.getMonth() && d1.getDate() == d2.getDate();
    }

    function parseDate(val) {
        if (!val) {
            return;
        }
        if (val.constructor == Date) {
            return val;
        }

        if (typeof val == 'string') {
            // rfc3339?
            var els = val.split(" ");
            var date, time;
            var y, m, d, h, s;
            date = els[0].split('-');
            if (date.length !== 3) {
                return;
            }
            if (els.length === 2) {
                time = els[1].split(':');
            } else {
                time = '00:00'.split(':');
            }
            y = date[0], m = date[1] - 1, d = date[2];
            h = time[0], s = time[1];
            return new Date(y, m, d, h, s, 0);
            // invalid offset
            if (!/^-?\d+$/.test(val)) {
                return;
            }
            // convert to integer
            val = integer(val);
        }
        var date = new Date();
        date.setDate(date.getDate() + val);
        return date;
    }

    function Plugin(input, options) {
        this.options = $.extend({}, defaults, options);
        this.input = input;
        this.init();
    }

    Plugin.prototype.init = function () {
        var options = this.options, input = this.input;
        if (options.time) {
            options.format = 'yyyy-mm-dd HH:MM'
        }
        // CSS prefix
        $.each(options.css, function (key, val) {
            if (!val && key != 'prefix') {
                options.css[key] = (options.css.prefix || '') + (val || key);
            }
        });
        // variables
        var self = this, now = new Date(), css = options.css, labels = LABELS[options.lang], root = $("#" + css.root), title = root.find("#" + css.title), trigger, pm, nm, currYear, currMonth, currDay, value = input.attr("data-value") || options.value || input.val(), min = input.attr("min") || options.min, max = input.attr("max") || options.max, opened;
        // zero min is not undefined
        if (min === 0) {
            min = "0";
        }
        // use sane values for value, min & max
        value = parseDate(value) || now;
        min = parseDate(min || options.yearRange[0] * 365);
        max = parseDate(max || options.yearRange[1] * 365);

        // check that language exists
        if (!labels) {
            throw "不存在的语言: " + options.lang;
        }

        // Replace built-in date input: NOTE: input.attr("type", "text") throws exception by the browser
        if (input.attr("type") === 'date') {
            var tmp = $("<input/>");

            $.each("class,disabled,id,maxlength,name,readonly,required,size,style,tabindex,title,value".split(","), function (i, attr) {
                tmp.attr(attr, input.attr(attr));
            });
            input.replaceWith(tmp);
            input = tmp;
        }
        input.addClass(css.input);

        var fire = input.add(self);

        // construct layout
        if (!root.length) {

            // root
            root = $('<div><div><a/><div/><a/></div><div><div/><div/></div></div>').hide().css({
                position: 'absolute'
            }).attr("id", css.root);

            // elements
            root.children().eq(0).attr("id", css.head).end().eq(1).attr("id", css.body).children().eq(0).attr("id", css.days).end().eq(1).attr("id", css.weeks).end().end().end().find("a").eq(0).attr("id", css.prev).end().eq(1).attr("id", css.next);

            // title
            title = root.find("#" + css.head).find("div").attr("id", css.title);

            // year & month selectors
            if (options.selectors) {
                var monthSelector = $("<select/>").attr("id", css.month), yearSelector = $("<select/>").attr("id", css.year);
                title.html(monthSelector.add(yearSelector));
            }

            // day titles
            var days = root.find("#" + css.days);

            // days of the week
            for (var d = 0; d < 7; d++) {
                days.append($("<span/>").text(labels.shortDays[(d + options.firstDay) % 7]));
            }

            var body = root.find("#" + css.body);
            $('<div class="caltime"><button type="button" class="btn btn_submit fr" name="submit">确认</button><input id="calHour" type="number" class="input" min="0" max="23" size="2" value="0"><span>点</span><input id="calMin" class="input" type="number" size="2" min="1" max="59" value="0"><span>分</span></div>').appendTo(body);

            $("body").append(root);

        }

        // trigger icon
        if (options.trigger) {
            trigger = $("<a/>").attr("href", "#").addClass(css.trigger).click(function (e) {
                self.show();
                return e.preventDefault();
            }).insertAfter(input);
        }

        // layout elements
        var weeks = root.find("#" + css.weeks);
        yearSelector = root.find("#" + css.year);
        monthSelector = root.find("#" + css.month);

        //{{{ pick

        function select(date, options, e) {
            if (!date) return;
            // current value
            value = date;
            currYear = date.getFullYear();
            currMonth = date.getMonth();
            currDay = date.getDate();

            if (e.type == "click" && $.browser && !$.browser.msie) {
                input.focus();
            }

            // select
            e = e || $.Event("api");
            e.type = "select";

            fire.trigger(e, [date]);
            if (e.isDefaultPrevented()) {
                return;
            }
            //如果选项有时间，则加上时间
            if (options.time) {
                var timeInput = root.find('input');
                var hour = parseInt(timeInput.eq(0).val(), 10);
                var min = parseInt(timeInput.eq(1).val(), 10);
                if (isNaN(hour)) {
                    hour = 0;
                }
                if (isNaN(min)) {
                    min = 0;
                }
                if (hour < 10) {
                    hour = '0' + hour;
                } else if (hour < 0 || hour > 23) {
                    hour = '00';
                }
                if (min < 10) {
                    min = '0' + min;
                } else if (min < 0 || min > 59) {
                    min = '00';
                }
                date.setHours(hour);
                date.setMinutes(min);
            }
            // formatting
            var date = format(date, options.format, options.lang);
            input.val(date);
            // store value into input
            input.data("date", date);
            //设置val后，IE导致触发focus事件，导致窗口关闭后再次被打开
            setTimeout(function () {
                self.hide(e);
            }, 100);
        }

        //}}}

        //{{{ onShow

        function onShow(ev) {

            ev.type = "onShow";
            fire.trigger(ev);

            //快捷键处理
            $(document).bind("keydown.d", function (e) {

                if (e.ctrlKey) {
                    return true;
                }
                var key = e.keyCode;

                // backspace clears the value
                if (e.target == input[0]) {//如果是在当前input按back键，清除值并隐藏日历
                    if (key == 8 || key == 46) {
                        input.val("");
                        return self.hide(e);
                    }
                }
                // esc key
                if (key == 27) {
                    return self.hide(e);
                }
                //如果有time，则不要快捷键
                if (options.time) {
                    return;
                }
                if ($(KEYS).index(key) >= 0) {

                    if (!opened) {
                        self.show(e);
                        return e.preventDefault();
                    }

                    var days = $("#" + css.weeks + " a"), el = $("." + css.focus), index = days.index(el);

                    el.removeClass(css.focus);

                    if (key == 74 || key == 40) {
                        index += 7;
                    } else if (key == 75 || key == 38) {
                        index -= 7;
                    } else if (key == 76 || key == 39) {
                        index += 1;
                    } else if (key == 72 || key == 37) {
                        index -= 1;
                    }

                    if (index > 41) {
                        self.addMonth();
                        el = $("#" + css.weeks + " a:eq(" + (index - 42) + ")");
                    } else if (index < 0) {
                        self.addMonth(-1);
                        el = $("#" + css.weeks + " a:eq(" + (index + 42) + ")");
                    } else {
                        el = days.eq(index);
                    }

                    el.addClass(css.focus);
                    return e.preventDefault();

                }

                // pageUp / pageDown
                if (key == 34) {
                    return self.addMonth();
                }
                if (key == 33) {
                    return self.addMonth(-1);
                }

                // home
                if (key == 36) {
                    return self.today();
                }

                // enter
                if (key == 13) {
                    if (!$(e.target).is("select")) {
                        $("." + css.focus).dblclick();
                    }
                }

                return $([16, 17, 18, 9]).index(key) >= 0;
            });

            // 点击外部关闭窗口
            /*$(document).bind("mousedown.d", function(e) {
             var el = e.target;

             if(!$(el).parents("#" + css.root).length && el != input[0] && (!trigger || el != trigger[0])) {
             self.hide(e);
             }

             });*/

            $(document.body).on("mousedown.d", function (e) {
                if (e.target !== input[0] && !$.contains(root[0], e.target)) {
                    setTimeout(function () {
                        self.hide();
                    }, 100)
                }
            });
        }

        //}}}

        $.extend(self, {

            //{{{  show

            show: function (e) {
                if (input.prop("readonly") || input.prop("disabled") || opened) {
                    return;
                }
                // onBeforeShow
                e = e || $.Event();
                e.type = "onBeforeShow";
                fire.trigger(e);
                if (e.isDefaultPrevented()) {
                    return;
                }

                $.each(instances, function () {
                    this.hide();
                });
                opened = true;

                // 月份下拉菜单
                monthSelector.unbind("change").change(function () {
                    self.setValue(yearSelector.val(), $(this).val());
                });
                // 年下拉菜单
                yearSelector.unbind("change").change(function () {
                    self.setValue($(this).val(), monthSelector.val());
                });
                // 上一月/下一月按钮
                pm = root.find("#" + css.prev).unbind("click").click(function (e) {
                    if (!pm.hasClass(css.disabled)) {
                        self.addMonth(-1);
                    }
                    return false;
                });
                nm = root.find("#" + css.next).unbind("click").click(function (e) {
                    if (!nm.hasClass(css.disabled)) {
                        self.addMonth();
                    }
                    return false;
                });
                // 设置日期
                self.setValue(value);

                //是否显示时间选择
                if (options.time) {
                    root.find('div.caltime').show();
                } else {
                    root.find('div.caltime').hide();
                }

                // show calendar
                var pos = input.offset();

                // iPad position fix
                if (/iPad/i.test(navigator.userAgent)) {
                    pos.top -= $(window).scrollTop();
                }
                var top = pos.top + input.outerHeight() + options.offset[0];
                if (top + root.height() > $(window).scrollTop() + $(window).height()) {
                    top = pos.top - root.height();
                }
                root.css({
                    top: top,
                    left: pos.left + options.offset[1]
                });

                if (options.speed) {
                    root.show(options.speed, function () {
                        onShow(e);
                    });
                } else {
                    root.show();
                    onShow(e);
                }

                return self;
            },
            //}}}

            //{{{  setValue

            setValue: function (year, month, day, hour, minute) {
                var date = integer(month) >= -1 ? new Date(integer(year), integer(month), integer(day || 1)) : year || value;

                if (date < min) {
                    date = min;
                } else if (date > max) {
                    date = max;
                }
                year = date.getFullYear();
                month = date.getMonth();
                day = date.getDate();
                hour = date.getHours();
                minute = date.getMinutes();
                // roll year & month
                if (month == -1) {
                    month = 11;
                    year--;
                } else if (month == 12) {
                    month = 0;
                    year++;
                }

                if (!opened) {
                    select(date, options);
                    return self;
                }
                currMonth = month;
                currYear = year;

                // variables
                var tmp = new Date(year, month, 1 - options.firstDay), begin = tmp.getDay(), days = dayAm(year, month), prevDays = dayAm(year, month - 1), week;

                // selectors
                if (options.selectors) {

                    // month selector
                    monthSelector.empty();
                    $.each(labels.months, function (i, m) {
                        if (min < new Date(year, i + 1, -1) && max > new Date(year, i, 0)) {
                            monthSelector.append($("<option/>").html(m).attr("value", i));
                        }
                    });
                    // year selector
                    yearSelector.empty();
                    var yearNow = now.getFullYear();

                    for (var i = yearNow + options.yearRange[0]; i < yearNow + options.yearRange[1]; i++) {
                        if (min <= new Date(i + 1, -1, 1) && max > new Date(i, 0, 0)) {
                            yearSelector.append($("<option/>").text(i));
                        }
                    }

                    monthSelector.val(month);
                    yearSelector.val(year);

                    // title
                } else {
                    title.html(labels.months[month] + " " + year);
                }

                // populate weeks
                weeks.empty();
                pm.add(nm).removeClass(css.disabled);

                // !begin === "sunday"
                for (var j = !begin ? -7 : 0, a, num; j < (!begin ? 35 : 42); j++) {
                    a = $("<a/>");

                    if (j % 7 === 0) {
                        week = $("<div/>").addClass(css.week);
                        weeks.append(week);
                    }

                    if (j < begin) {
                        a.addClass(css.off);
                        num = prevDays - begin + j + 1;
                        date = new Date(year, month - 1, num);

                    } else if (j >= begin + days) {
                        a.addClass(css.off);
                        num = j - days - begin + 1;
                        date = new Date(year, month + 1, num);

                    } else {
                        num = j - begin + 1;
                        date = new Date(year, month, num);

                        // current date
                        if (isSameDay(value, date)) {
                            a.attr("id", css.current).addClass(css.focus);

                            // today
                        } else if (isSameDay(now, date)) {
                            a.attr("id", css.today);
                        }
                    }

                    // disabled
                    if (min && date < min) {
                        a.add(pm).addClass(css.disabled);
                    }

                    if (max && date > max) {
                        a.add(nm).addClass(css.disabled);
                    }

                    a.attr("href", "#" + num).text(num).data("date", date);

                    week.append(a);

                    if (options.selectors) {
                        //console.log(year, month, day, hour, minute)
                    }
                }

                //时间选择
                //!TODO:chaoren1641增加，有待重构
                if (options.time) {
                    //如果有时间选项则点击确定或双击日期输入时间
                    // date picking
                    weeks.find("a").on('click', function (e) {
                        var el = $(this);
                        if (!el.hasClass(css.disabled)) {
                            $("#" + css.current).removeAttr("id");
                            el.attr("id", css.current);
                        }
                        return false;
                    }).off('dblclick').dblclick(function (e) {
                        var el = $(this);
                        if (!el.hasClass(css.disabled)) {
                            select(el.data("date"), options, e);
                            //在IE下，重新赋值会引起focus，导致日历控件再次激活打开，所以setTimeout下
                            setTimeout(function () {
                                self.hide();
                            }, 100);
                        }
                        return false;
                    });

                    var body = root.find("#" + css.body);
                    body.find('button').off('click.d').on('click.d', function (e) {
                        var el = root.find('#' + css.current);
                        select(el.data("date"), options, e);
                        //在IE下，重新赋值会引起focus，导致日历控件再次激活打开，所以setTimeout下
                        setTimeout(function () {
                            self.hide();
                        }, 100);
                        return false;
                    });
                    body.find('#calHour').val(hour);
                    body.find('#calMin').val(minute);
                } else {
                    // date picking
                    weeks.find("a").click(function (e) {
                        var el = $(this);
                        if (!el.hasClass(css.disabled)) {
                            $("#" + css.current).removeAttr("id");
                            el.attr("id", css.current);
                            select(el.data("date"), options, e);
                        }
                        return false;
                    })
                }
                // sunday
                if (css.sunday) {
                    weeks.find(css.week).each(function () {
                        var beg = options.firstDay ? 7 - options.firstDay : 0;
                        $(this).children().slice(beg, beg + 1).addClass(css.sunday);
                    });
                }

                return self;
            },
            //}}}

            setMin: function (val, fit) {
                min = parseDate(val);
                if (fit && value < min) {
                    self.setValue(min);
                }
                return self;
            },
            setMax: function (val, fit) {
                max = parseDate(val);
                if (fit && value > max) {
                    self.setValue(max);
                }
                return self;
            },
            today: function () {
                return self.setValue(now);
            },
            addDay: function (amount) {
                return this.setValue(currYear, currMonth, currDay + (amount || 1));
            },
            addMonth: function (amount) {
                return this.setValue(currYear, currMonth + (amount || 1), currDay);
            },
            addYear: function (amount) {
                return this.setValue(currYear + (amount || 1), currMonth, currDay);
            },
            hide: function (e) {
                if (opened) {
                    // onHide
                    e = $.Event();
                    e.type = "onHide";
                    fire.trigger(e);

                    $(document).unbind("click.d").unbind("keydown.d");

                    // cancelled ?
                    if (e.isDefaultPrevented()) {
                        return;
                    }

                    // do the hide
                    root.hide();
                    opened = false;
                }

                return self;
            },
            getConf: function () {
                return options;
            },
            getInput: function () {
                return input;
            },
            getCalendar: function () {
                return root;
            },
            getValue: function (dateFormat) {
                return dateFormat ? format(value, dateFormat, options.lang) : value;
            },
            isOpen: function () {
                return opened;
            }
        });

        // callbacks
        $.each(['onBeforeShow', 'onShow', 'select', 'onHide'], function (i, name) {

            // configuration
            if ($.isFunction(options[name])) {
                $(self).bind(name, options[name]);
            }

            // API methods
            self[name] = function (fn) {
                if (fn) {
                    $(self).bind(name, fn);
                }
                return self;
            };
        });
        // show dateinput & assign keyboard shortcuts
        input.bind("focus click", self.show).keydown(function (e) {
            var key = e.keyCode;

            // open dateinput with navigation keyw
            if (!opened && $(KEYS).index(key) >= 0) {
                self.show(e);
                return e.preventDefault();
            }

            // allow tab
            return e.shiftKey || e.ctrlKey || e.altKey || key == 9 ? true : e.preventDefault();

        });
        // initial value
        if (parseDate(input.val())) {
            //!TODO关闭初始化的值，这里会出现BUG
            //select(value, options);
        }
    };

    $.expr[':'].date = function (el) {
        var type = el.getAttribute("type");
        return type && type == 'date' || !!$(el).data("dateinput");
    };


    $.fn[pluginName] = function (options) {
        Wind.css('datePicker');
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                var instance = new Plugin($(this), options);
                instances.push(instance);
                $.data(this, 'plugin_' + pluginName, instance);
            }
        });
    };

    /*$.fn.dateinput = function(conf) {


     // already instantiated
     if(this.data("dateinput")) {
     return this;
     }

     // configuration
     conf = $.extend(true, {}, tool.conf, conf);

     // CSS prefix
     $.each(conf.css, function(key, val) {
     if(!val && key != 'prefix') {
     conf.css[key] = (conf.css.prefix || '') + (val || key);
     }
     });
     var els;

     this.each(function() {
     var el = new Dateinput($(this), conf);
     instances.push(el);
     var input = el.getInput().data("dateinput", el);
     els = els ? els.add(input) : input;
     });
     return els ? els : this;
     };*/


})(jQuery, window, document);
